#include <iostream>

#include "Vector2D.h"
#include "Vector3D.h"
#include "Rectangle.h"
#include "Cercle.h"
#include "LineSegment.h"

using namespace std;

void main()
{
	//VECTOR 2D
	std::cout << "+++++ Vector2D tests +++++" << std::endl;
	cout << endl;
	{
		std::cout << "Simple addition : u + (-u) = {20, 9} : " ;
		Vector2D u = {4, 2};
		Vector2D v = {16, 7};
		Vector2D add = Vector2D::Add(u, v);
		Vector2D r = {20, 9};
		if (Vector2D::Equals(add, r))
		{
			std::cout << "OK" << std::endl;
		} 
		else 
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "Simple substraction : u - u = 0 : " ;
		Vector2D u = {4, -2};
		Vector2D sub = Vector2D::Substract(u, u);
		Vector2D r = {0, 0};
		if (Vector2D::Equals(sub, r)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "Scale : 2u = {8, -4} : " ;
		Vector2D u = {4, -2};
		Vector2D grandeur = Vector2D::Scale(u, 2);
		Vector2D r = {8, -4};
		if (Vector2D::Equals(grandeur, r)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "MoveBy : {1, 1} + {4.15, -4} = {5.15, -3} : " ;
		Vector2D by = {1, 1};
		Vector2D toMove = {4.5, -4};
		Vector2D::MoveBy(by, toMove);
		Vector2D r = {5.5, -3};
		if (Vector2D::Equals(toMove, r)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{ 
		std::cout << "GetPolarAngleDeg : {-1, 1} : 135 : " ;
		Vector2D vect = {-1, 1};
		Vector2D::GetPolarAngleDeg(vect);
		float r = 135;
		float getPolar = Vector2D::GetPolarAngleDeg(vect);
		if (getPolar == r)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{ 
		std::cout << "AngleBetweenDeg : {0, 0} = 0 : " ;
		Vector2D left = {1, 0};
		Vector2D right = {1, 0};
		Vector2D::AngleBetweenDeg(left, right);
		float r = 0;
		float betDeg = Vector2D::AngleBetweenDeg(left, right);
		if (betDeg == r)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{ 
		std::cout << "AngleBetweenDeg : {1, 0}, {0, 1} = 90 : " ;
		Vector2D left = {1, 0};
		Vector2D right = {0, 1};
		Vector2D::AngleBetweenDeg(left, right);
		float r = 90;
		float betDeg = Vector2D::AngleBetweenDeg(left, right);
		if (betDeg == r)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "Length : {5, 8} = 9.43398 : ";	
		Vector2D vect = {5, 8};
		Vector2D::Length(vect);
		float r = 9.43398f;
		float mLength = Vector2D::Length(vect);
		if (fabs(mLength - r) < EPSILON)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "LengthSq : {4, -2} = 20 : " ;
		Vector2D vect = {4, -2};
		Vector2D::LengthSq(vect);
		float r = 20;
		float mLengthSq = Vector2D::LengthSq(vect);
		if (fabs(mLengthSq - r) < EPSILON) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{ 
		std::cout << "Normalize : {0, 0} = ERROR : " ;
		Vector2D vect = {0, 0};
		if (!Vector2D::Normalize(vect) == true)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{ 
		std::cout << "Normalize : {1, 10} = 0 : " ;
		Vector2D vect = {1, 10};
		if (Vector2D::Normalize(vect) == true)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "ScaleBy : 2 * {4.25, -4} = {8.50, -8} : " ;
		Vector2D vect = {4.25, -4};
		Vector2D::ScaleBy(vect, 2);
		Vector2D r = {8.50, -8};
		if (Vector2D::Equals(vect, r)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "GetVectorByAngleDeg : 180 = {-1, 0} : " ;
		float angle = 180;
		Vector2D r = {-1, 0};
		if (Vector2D::Equals(Vector2D::GetVectorByAngleDeg(angle), r)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}




	//VECTOR 3D
	cout << endl;
	cout << "+++++ Vector3D tests +++++" << std::endl;
	cout << endl;
	{
		cout << "Simple Addition : u + (-u) = 0 : " ;
		Vector3D u = {-1, 2, 3};
		Vector3D v = {1, -2, -3};
		Vector3D add = Vector3D::Add(u, v);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(add, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Simple addition : (20, 15, -10) + (-80, 30.5, 5.5) = (-60, 45.5, -4.5): " ;
		Vector3D u = {20, 15, -10};
		Vector3D v = {-80, 30.5, 5.5};
		Vector3D add = Vector3D::Add(u, v);
		Vector3D r = {-60, 45.5, -4.5};
		if (Vector3D::Equals(add, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Simple substraction : u - u = 0 : " ;
		Vector3D u = {100, -99, 5.5};
		Vector3D sub = Vector3D::Substract(u, u);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(sub, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Simple substraction : u - v : " ;
		Vector3D u = {20, 15, -10};
		Vector3D v = {-80, 30.5, -10.5};
		Vector3D sub = Vector3D::Substract(u, v);
		Vector3D r = {100, -15.5, 0.5};
		if (Vector3D::Equals(sub, r)) 
		{
			cout << "OK" << endl;;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Scale : 2u = (-2, 4, 6) : " ;
		Vector3D u = {-1, 2, 3};
		Vector3D scale = Vector3D::Scale(u, 2);
		Vector3D r = {-2, 4, 6};
		if (Vector3D::Equals(scale, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Scale : 0u = (0, 0, 0) : " ;
		Vector3D u = {1, 2, 3};
		Vector3D scale = Vector3D::Scale(u, 0);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(scale, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Scale : 0u = (0, 0, 0) : " ;
		Vector3D u = {1, 2, 3};
		Vector3D scale = Vector3D::Scale(u, 0);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(scale, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Dot : u dot v = 10 : " ;
		Vector3D u = {1, 2, 3};
		Vector3D v = {3, 2, 1};
		float dot = Vector3D::Dot(u, v);
		float r = 10;
		if (dot == r) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{
		cout << "Dot : u dot v = 0 : " ;
		Vector3D u = {1, -2, 2};
		Vector3D v = {2, 2, 1};
		float dot = Vector3D::Dot(u, v);
		float r = 0;
		if (dot == r) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "CrossLH : {1, 2, 3} x {3, 2, 1} : " ;
		Vector3D u = {1, 2, 3};
		Vector3D v = {3, 2, 1};
		Vector3D cross = Vector3D::CrossLH(u, v);
		Vector3D r = {-4, 8, 4};
		if (Vector3D::Equals(cross, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "CrossLH : u x v = 0: " ;
		Vector3D u = {1, 1, 1};
		Vector3D v = {3, 3, 3};
		Vector3D cross = Vector3D::CrossLH(u, v);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(cross, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

		{		
		cout << "CrossRH : {1, 2, 3} x {3, 2, 1} : " ;
		Vector3D u = {1, 2, 3};
		Vector3D v = {3, 2, 1};
		Vector3D cross = Vector3D::CrossRH(u, v);
		Vector3D r = {-4, 8, -4};
		if (Vector3D::Equals(cross, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "CrossRH : u x v = 0: " ;
		Vector3D u = {1, 1, 1};
		Vector3D v = {3, 3, 3};
		Vector3D cross = Vector3D::CrossRH(u, v);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(cross, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "ToMove : toMove{0, 0, 0} by {3, -4, 10} : " ;
		Vector3D toMove = {0, 0, 0};
		Vector3D by = {3, -4, 10};
		Vector3D::MoveBy(by, toMove);
		Vector3D r = {3, -4, 10};
		if (Vector3D::Equals(toMove, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "ToMove : toMove{0, 0, 0} by {0, 0, 0} : " ;
		Vector3D toMove = {0, 0, 0};
		Vector3D by = {0, 0, 0};
		Vector3D::MoveBy(by, toMove);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(toMove, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Length u = 11.1803 : " ;
		Vector3D u = {3, -4, 10};
		float length = Vector3D::Length(u);
		float r = 11.1803f;
		if ((fabs(length - r)) < EPSILON) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Length u = 0 : " ;
		Vector3D u = {0, 0, 0};
		float length = Vector3D::Length(u);
		float r = 0;
		if (length == r) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "LengthSq u = 125 : " ;
		Vector3D u = {3, -4, 10};
		float lengthSq = Vector3D::LengthSq(u);
		float r = 125;
		if (lengthSq == r) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "LengthSq u = 0 : " ;
		Vector3D u = {0, 0, 0};
		float lengthSq = Vector3D::LengthSq(u);
		float r = 0;
		if (lengthSq == r) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Normalize u {3, -4, 10} : " ;
		Vector3D u = {3, -4, 10};
		Vector3D::Normalize(u);
		Vector3D r = {0.2683f, -0.3577f, 0.8944f};
		if (Vector3D::Equals(u, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Normalize u {0, 0, 0} = ERROR : " ;
		Vector3D u = {0, 0, 0};
		if (!Vector3D::Normalize(u)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Scale u by -5 = {-15, 20, -50} : " ;
		Vector3D u = {3, -4, 10};
		Vector3D::ScaleBy(u, -5);
		Vector3D r = {-15, 20, -50};
		if (Vector3D::Equals(u, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}

	{		
		cout << "Scale u by 0 = {0, 0, 0} : " ;
		Vector3D u = {3, -4, 10};
		Vector3D::ScaleBy(u, 0);
		Vector3D r = {0, 0, 0};
		if (Vector3D::Equals(u, r)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}
	}
	//RECTANGLES
	cout << endl;
	cout << "+++++ Rectangle tests +++++" << std::endl;
	cout << endl;
	{		
		cout << "Rectangle (Default Constructor) Contains point : " ;
		Rectangle2 rect1(0,0,1,1);
			
		if (rect1.Contains(0,0)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle (Constructor Vectors) Contains point : " ;
		Vector2D topLeft = {0, 0};
		Vector2D btmRight = {1, 1};
		Rectangle2 rect1(topLeft, btmRight);
			
		if (rect1.Contains(0,0)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}
		
	{		
		cout << "Rectangle (Default Constructor) Contains Vector : " ;
		Vector2D toContain = {5,5};
		Rectangle2 rect1(4,4,5,5);
			
		if (rect1.Contains(0,0)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle (Constructor Vectors) Contains Vector : " ;
		Vector2D topLeft = {0, 0};
		Vector2D btmRight = {2, 2};
		Vector2D toContain = {1,1};
		Rectangle2 rect1(topLeft,btmRight);
			
		if (rect1.Contains(toContain)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle SetPosition(Vector) : " ;
		Vector2D setPosition = {9,9};
		Rectangle2 rect1(4,4,5,5);
		rect1.SetPosition(setPosition);
			
		if (rect1.GetX() == 9 && rect1.GetY() == 9) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle SetPosition(x,y) : " ;
		Rectangle2 rect1(4,4,5,5);
		rect1.SetPosition(10,-7);
			
		if (rect1.GetX() == 10 && rect1.GetY() == -7) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle MoveBy(Vector) : " ;
		Vector2D moveBy = {9,9};
		Rectangle2 rect1(4,4,5,5);
		rect1.MoveBy(moveBy);
			
		if (rect1.GetX() == 13 && rect1.GetY() == 13) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle MoveBy(x,y) : " ;
		Rectangle2 rect1(4,4,5,5);
		rect1.MoveBy(10,-4);
			
		if (rect1.GetX() == 14 && rect1.GetY() == 0) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle CollidesWith : " ;
		Rectangle2 rect1(4,4,5,5);
		Rectangle2 rect2(4,4,5,5);
			
		if (rect1.CollidesWith(rect2)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

	{		
		cout << "Rectangle Doesn't CollidesWith : " ;
		Rectangle2 rect1(4,4,5,5);
		Rectangle2 rect2(-10,-10,5,5);
			
		if (!rect1.CollidesWith(rect2)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}


	//CERCLE
	cout << endl;
	cout << "+++++ Circle tests +++++" << std::endl;
	cout << endl;
	{
		std::cout << "Contains : {2,4}: " ;
		Circle2 circ(2,4,5);
		if (circ.Contains(2,4)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "Vector Contains : {2,4}: " ;
		Vector2D vect = {5,6};
		Circle2 circ(vect,6);
		if (circ.Contains(2,4)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}
	
	{
		std::cout << "SetPosition : {3,3}: " ;
		Vector2D setPosition = {3,3};
		Vector2D vect = {5,6};
		Circle2 circ(vect,6);
		circ.SetPosition(setPosition);

		if (circ.GetX() == 3 && circ.GetY() == 3)
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}
	
	{
		std::cout << "SetPosition : {2,2}: " ;
		Circle2 circ(4,5,6);
		Vector2D setPosition = {2,2};
		circ.SetPosition(setPosition);
		if (circ.GetX() == 2 && circ.GetY() == 2) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}
	
	{
		std::cout << "MoveBy : {7,8}: " ;
		Vector2D moveBy = {2,2};
		Vector2D vect = {5,6};
		Circle2 circ(vect,4);
		circ.MoveBy(moveBy);
		if (circ.GetX() == 7 && circ.GetY() == 8) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}
	
	{
		std::cout << "MoveBy : {7,6}: " ;
		Vector2D moveBy = {2,2};
		Circle2 circ(5,4,4);
		circ.MoveBy(moveBy);
		if (circ.GetX() == 7 && circ.GetY() == 6) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}

	{
		std::cout << "CollidesWith : {4,5,10} et {3,2,10}: " ;
		Circle2 circ(4,5,10);
		Circle2 circ2(3,2,10);
		if (circ2.CollidesWith(circ)) 
		{
			std::cout << "OK" << std::endl;
		} 
		else
		{
			std::cout << "FAILED !" << std::endl;
		}
	}	
	
	//BONUS
	cout << endl;
	cout << "+++++ LineSegment tests +++++" << std::endl;
	cout << endl;
	{		
		cout << "LineSegment IntersectsWith : " ;
		Vector2D from = {0,0};
		Vector2D to = {5,5};
		LineSegment lineSeg1(from,to);
		LineSegment lineSeg2(5,0,0,5);
					
		if (lineSeg1.IntersectsWith(lineSeg2)) 
		{
			cout << "OK" << endl;
		} else 
		{
			cout << "FAILED !" << endl;
		}		
	}

}
